package com.jamiexu.help.socket.client;

import com.jamiexu.help.socket.javabean.FileBean;
import com.jamiexu.help.socket.utils.OperationUtils;
import com.jamiexu.help.socket.utils.SocketUtils;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import javafx.util.Callback;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.ArrayList;

public class Main extends Application {


    //绑定控件
    @FXML
    public TextField server_ip;

    @FXML
    public TextField server_port;

    @FXML
    public Button connected;

    @FXML
    public TableView list_file;

    private Socket socket;


    //存放数据的list
    private final ObservableList observableList = FXCollections.observableArrayList();


    //当前是否正在下载
    private boolean isDownload = false;


    //当前下载的文件名
    private String currentDownloadName = "";

    //文件下载后保存地址
    private final String DOWNLOAD_PATH = "C:\\Users\\1\\Desktop\\";

    //当前下载的文件序号
    private int currentDownloadNum;


    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));//从文件导入场景布局
        primaryStage.setTitle("文件接收端");//设置标题
        primaryStage.setScene(new Scene(root, 600, 400));//新建舞台
        primaryStage.setMaxWidth(600);//设置最大宽度
        primaryStage.setMaxHeight(400);//设置最大高
        primaryStage.setMinWidth(600);//设置最小宽度
        primaryStage.setMinHeight(400);//设置最小高度
        primaryStage.show();//显示窗口
    }


    //按钮点击事件
    @FXML
    public void connect() {
        if (connected.getText().equals("已连接")) { //如果连接了后再点击按钮就关闭
            try {
                this.socket.close();//关闭socket连接
                connected.setText("连接");//更改按钮文字
            } catch (IOException e) {
                e.printStackTrace();
            }
            ;
            return;
        }

        String port = this.server_port.getText(); //获取编辑框的内容
        String ip = this.server_ip.getText(); //获取编辑框的内容
        if (ip.equals("") || port.equals(""))//判断内容是否为空
            return;

        if (port.matches("[^\\d]+"))//ip是否为纯数字
            return;

        try {
            this.socket = new Socket(ip, Integer.parseInt(port));//开始连接
            SocketUtils.sendOPData(this.socket, OperationUtils.OP_CONNECT_CONNECT, OperationUtils.HEAD, null);//发送连接指令
            new Thread(() -> {
                while (true) {
                    byte[] data = SocketUtils.getData(socket);//获取服务器返回的数据
                    if (data == null)
                        continue;
                    Object[] block = SocketUtils.getBlock(data);//分块处理
                    processOp(socket, block);//处理指令
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void processOp(Socket socket, Object[] block) {
        try {
            FileOutputStream fileOutputStream = null;
            String op = (String) block[0];//获取指令
            String head = (String) block[1];//获取报头
            byte[] data = (byte[]) block[2];//获取数据
            int ver = (int) block[3];//获取校验值
            System.out.println("服务端：" + op);


            //以下是判断指令进行执行操作
            if (op.equals(OperationUtils.OP_CONNECT_ACCEPT)) {
                Platform.runLater(() -> {
                    this.connected.setText("已连接");
                    getFileList(socket);
                });
            } else if (op.equals(OperationUtils.OP_FILE_LIST)) {
                ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
                ArrayList<FileBean> fileBeans = (ArrayList<FileBean>) objectInputStream.readObject();
                objectInputStream.close();

                observableList.addAll(fileBeans);

            } else if (op.equals(OperationUtils.OP_FILE_START)) {
                isDownload = true;
                FileBean fileBean = (FileBean) observableList.get(currentDownloadNum);
                fileBean.setStatus("下载中...");
                observableList.set(currentDownloadNum, fileBean);
            } else if (op.equals(OperationUtils.OP_FILE)) {
                FileBean fileBean = (FileBean) observableList.get(currentDownloadNum);
                fileBean.setCurrentBlock(Integer.parseInt(head.split("\r\n")[2]));
                observableList.set(currentDownloadNum, fileBean);
                fileOutputStream = new FileOutputStream(DOWNLOAD_PATH + currentDownloadName, true);
                fileOutputStream.write(data);
            } else if (op.equals(OperationUtils.OP_FILE_FINISH)) {
                FileBean fileBean = (FileBean) observableList.get(currentDownloadNum);
                fileBean.setStatus("已下载");
                observableList.set(currentDownloadNum, fileBean);
                isDownload = false;
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    //从服务器获取文件列表
    public void getFileList(Socket socket) {
        observableList.clear();
        SocketUtils.sendOPData(socket, OperationUtils.OP_GET_FILE, OperationUtils.HEAD, null);
    }

    //从服务器获取文件
    public void getFile(Socket socket, int num) {
        SocketUtils.sendOPData(socket, OperationUtils.OP_DOWNLOAD_FILE, OperationUtils.HEAD + num, null);
    }

    @FXML
    public void initialize() {

        TableColumn num = (TableColumn) this.list_file.getColumns().get(0);
        num.setCellValueFactory(new PropertyValueFactory<>("num"));

        TableColumn fileName = (TableColumn) this.list_file.getColumns().get(1);
        fileName.setCellValueFactory(new PropertyValueFactory<>("fileName"));

        TableColumn size = (TableColumn) this.list_file.getColumns().get(2);
        size.setCellValueFactory(new PropertyValueFactory<>("size"));

        TableColumn block_num = (TableColumn) this.list_file.getColumns().get(3);
        block_num.setCellValueFactory(new PropertyValueFactory<>("block_num"));

        TableColumn currentBlock = (TableColumn) this.list_file.getColumns().get(4);
        currentBlock.setCellValueFactory(new PropertyValueFactory<>("currentBlock"));

        TableColumn status = (TableColumn) this.list_file.getColumns().get(5);
        status.setCellValueFactory(new PropertyValueFactory<>("status"));


        this.list_file.setItems(observableList);

        this.list_file.setRowFactory(new Callback<TableView<FileBean>, TableRow<FileBean>>() {
            @Override
            public TableRow<FileBean> call(TableView<FileBean> param) {
                TableRow<FileBean> tableRow = new TableRow<>();
                tableRow.setOnMouseClicked(new EventHandler<MouseEvent>() {
                    @Override
                    public void handle(MouseEvent event) {
                        if (event.getClickCount() == 2 && (!tableRow.isEmpty())) {
                            FileBean fileBean = tableRow.getItem();
                            currentDownloadName = fileBean.getFileName();
                            currentDownloadNum = fileBean.getNum() - 1;
                            if (!isDownload)
                                getFile(socket, fileBean.getNum());
                        }
                    }
                });
                return tableRow;
            }
        });
    }


    @FXML
    public void listfile() {
        getFileList(socket);
    }


    public static void main(String[] args) {
        launch(args);
    }
}
